package com.superbit.service.match.impl;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;

import org.apache.commons.codec.binary.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.superbit.core.constant.TradeLogConstants;
import com.superbit.core.dto.ComplainDetailDto;
import com.superbit.core.dto.OrderDetailDto;
import com.superbit.core.dto.TradeLogListDto;
import com.superbit.core.entry.UserPayMethod;
import com.superbit.core.entry.UserSafeInfo;
import com.superbit.core.entry.tradelog.ComplainLog;
import com.superbit.core.entry.tradelog.TradeLog;
import com.superbit.core.service.ChatLogService;
import com.superbit.core.service.TradeLogService;
import com.superbit.core.service.UserAssetService;
import com.superbit.core.service.UserBaseInfoProxy;
import com.superbit.core.service.UserPayMethodProxy;
import com.superbit.core.service.UserSafeInfoProxy;
import com.superbit.core.service.UserTradeRecordProxy;
import com.superbit.service.match.daodefine.ComplainLogDao;
import com.superbit.service.match.daodefine.TradeLogDao;
import com.superbit.service.util.GenerateUtils;
import com.superbit.utils.date.DateFormateUtils;

/**
 * 交易记录服务类接口实现类
 * 
 * @author zhangdaoguang
 *
 */
@Service("tradeLogService")
@Transactional
public class TradeLogServiceImpl implements TradeLogService {
	private static Logger log = LoggerFactory
			.getLogger(TradeLogServiceImpl.class);

	@Autowired
	private TradeLogDao tradeLogDao;

	@Autowired
	private ComplainLogDao complainLogDao;

	@Autowired
	private UserBaseInfoProxy userBaseInfoProxy;

	@Autowired
	private UserPayMethodProxy userPayMethodProxy;

	@Autowired
	private UserSafeInfoProxy userSafeInfoProxy;

	@Autowired
	private UserAssetService userAssetService;

	@Autowired
	private UserTradeRecordProxy userTradeRecordProxy;

	@Autowired
	private ChatLogService chatLogService;

	@Override
	public Long saveTradeLog(TradeLog tradeLog) {
		final Long tradeLogId = this.tradeLogDao.saveTradeLog(tradeLog);

		/**
		 * 超时未支付则变为超时取消状态取消
		 */
		Timer timer = new Timer();
		TimerTask task = new TimerTask() {
			@Override
			public void run() {
				log.info("start run...");
				TradeLog tradeLog = tradeLogDao.getTradeLogById(tradeLogId);
				if (tradeLog != null
						&& TradeLogConstants.PAY_STATUS_NOT_PAY.equals(tradeLog
								.getPayStatus())) {
					log.info("not pay,cancel trade log id: {}", tradeLogId);
					tradeLog.setPayStatus(TradeLogConstants.PAY_STATUS_TIMEOUT_CANCEL);
					tradeLog.setCancelTime(new Timestamp(System
							.currentTimeMillis()));
					tradeLog.setUpdateTime(new Timestamp(System
							.currentTimeMillis()));
					tradeLogDao.updateTradeLog(tradeLog);

					// 更新交易记录次数
					userTradeRecordProxy.reduceTradCount(tradeLog
							.getBuyserUid());
				}
				log.info("run end!");
			}
		};
		// 5分钟后调度执行
		timer.schedule(task, TradeLogConstants.AUTO_CANCEL_TIME);
		log.info("TradeLogServiceImpl.saveTradeLog() success! saveId:{}",
				tradeLogId);
		return tradeLogId;
	}

	@Override
	public TradeLog getInitTradeLog() {
		TradeLog tradeLog = new TradeLog();
		tradeLog.setOrderNumber(GenerateUtils.genOrderNumber());
		tradeLog.setPayStatus(TradeLogConstants.PAY_STATUS_NOT_PAY);
		tradeLog.setHasComplain(TradeLogConstants.HAVE_COMPLAIN_NO);
		tradeLog.setCreateTime(new Timestamp(System.currentTimeMillis()));
		tradeLog.setUpdateTime(new Timestamp(System.currentTimeMillis()));
		return tradeLog;
	}

	@Override
	public List<TradeLogListDto> getTradeLogList(Integer userId,
			Integer tradeType, Integer payStatus, Integer hasComplain,
			Long payNumber, String coinCode, Integer pageNo, Integer pageSize) {
		List<TradeLog> tradeLogList = new ArrayList<TradeLog>();
		// 付款参考号唯一(用的ID)
		if (payNumber != null) {
			TradeLog tradeLog = this.tradeLogDao.getTradeLogById(payNumber);
			if (tradeLog != null) {
				tradeLogList.add(tradeLog);
			}
		} else {
			tradeLogList = this.tradeLogDao.getTradeLogList(userId,tradeType,
					payStatus, coinCode, hasComplain, pageNo, pageSize);
		}

		// 填充tradelog数据
		List<TradeLogListDto> retDtos = new ArrayList<TradeLogListDto>();
		List<String> orderNumbers = new ArrayList<String>();
		for (TradeLog log : tradeLogList) {
			TradeLogListDto dto = new TradeLogListDto(log);
			dto.setTradeUserName(userBaseInfoProxy.getNickNameByUserId(dto
					.getTradeUserId()));
			retDtos.add(dto);
			orderNumbers.add(log.getOrderNumber());
		}

		// 有申诉补充申诉的数据complainlog
		if (TradeLogConstants.HAVE_COMPLAIN_YES.equals(hasComplain)) {
			Map<String, ComplainLog> complainLogMap = this.complainLogDao
					.getComplainLogByOrdernumbers(orderNumbers);
			for (TradeLogListDto listDto : retDtos) {
				ComplainLog complainLog = complainLogMap.get(listDto
						.getOrderNumber());
				if (complainLog != null) {
					listDto.setComplainPeopleId(complainLog.getUid());
					// 申诉人和交易对象是同一个人,说明申诉人是卖家
					if (complainLog.getUid().equals(listDto.getTradeUserId())) {
						listDto.setComplainPeople(TradeLogConstants.SELL_NAME);
					} else {
						listDto.setComplainPeople(TradeLogConstants.BUY_NAME);
					}
					listDto.setComplainPeopleName(userBaseInfoProxy
							.getNickNameByUserId(listDto.getComplainPeopleId()));
					listDto.setComplainStatus(complainLog.getComplainStatus());
				}
			}
		}

		// 填充聊天图标数据
		Map<String, Integer> hasMsgMap = this.chatLogService
				.hasNewMessage(orderNumbers);
		for (TradeLogListDto dto : retDtos) {
			dto.setHasNewMessage(hasMsgMap.get(dto.getOrderNumber()));
		}
		return retDtos;
	}

	@Override
	public OrderDetailDto getOrderDetail(String orderNumber) {
		TradeLog tradeLog = this.tradeLogDao.getTradeLogByOrderNum(orderNumber);
		if (tradeLog == null) {
			return null;
		}

		OrderDetailDto detailDto = new OrderDetailDto();
		BeanUtils.copyProperties(tradeLog, detailDto);
		detailDto.setPayNumber(tradeLog.getId());
		detailDto.setPayTime(DateFormateUtils.formate(tradeLog.getPayTime()));
		detailDto.setDoneTime(DateFormateUtils.formate(tradeLog.getDoneTime()));

		if (TradeLogConstants.HAVE_COMPLAIN_YES.equals(tradeLog
				.getHasComplain())) {
			ComplainLog complainLog = this.complainLogDao
					.getComplainLogByOrdernumber(orderNumber);
			if (complainLog != null) {
				detailDto.setComplainTime(DateFormateUtils.formate(complainLog
						.getCreateTime()));
			}
		}

		// 设置支付方式相关数据
		List<UserPayMethod> payMethonds = this.userPayMethodProxy
				.getUserPayMethodByUserId(tradeLog.getSellerUid());
		Map<String, String> wx = new HashMap<String, String>();
		Map<String, String> ali = new HashMap<String, String>();
		Map<String, String> card = new HashMap<String, String>();
		if (payMethonds != null) {
			for (UserPayMethod method : payMethonds) {
				if (TradeLogConstants.CNANEL_ID_WX.equals(method.getChanelID())) {
					wx.put("account", method.getPayAccount());
					wx.put("name", method.getRealName());
					wx.put("qrCode", method.getPayQrAddr());
				} else if (TradeLogConstants.CNANEL_ID_ALI.equals(method
						.getChanelID())) {
					ali.put("account", method.getPayAccount());
					ali.put("name", method.getRealName());
					ali.put("qrCode", method.getPayQrAddr());
				} else if (TradeLogConstants.CNANEL_ID_CARD.equals(method
						.getChanelID())) {
					card.put("account", method.getPayAccount());
					card.put("name", method.getRealName());
					card.put("bank", method.getPayQrCode());
					card.put("subbranch", method.getPayQrAddr());
				}
			}
		}
		detailDto.setWx(wx);
		detailDto.setAli(ali);
		detailDto.setCard(card);
		return detailDto;
	}

	@Override
	public Integer updateOrder(String orderNumber, Integer payStatus,
			String fundPassword) {
		TradeLog tradeLog = this.tradeLogDao.getTradeLogByOrderNum(orderNumber);
		if (tradeLog == null) {
			log.info(
					"TradeLogServiceImpl.updateOrder() orderNumber:{} trade log is null",
					orderNumber);
			return TradeLogConstants.TRADE_LOG_NOT_EXIST;
		}

		// 放币
		if (TradeLogConstants.PAY_STATUS_DONE.equals(payStatus)) {
			// 验证资金密码
			UserSafeInfo userInfo = this.userSafeInfoProxy
					.verificationSafeInfo(tradeLog.getSellerUid());
			if (userInfo == null
					|| !StringUtils.equals(userInfo.getFundPassword(),
							fundPassword)) {
				log.info(
						"TradeLogServiceImpl.updateOrder() inputPassword:{}, realPassword:{} not same",
						fundPassword, userInfo.getFundPassword());
				return TradeLogConstants.FUND_PASSWORD_ILLEGAL;
			}

			// 转移资产
			Integer result = userAssetService.transferFund(
					tradeLog.getSellerUid(), tradeLog.getBuyserUid(),
					tradeLog.getCoinCode(), tradeLog.getCoinAmount());
			if (result != 0) {
				return TradeLogConstants.FUND_TRANSFER_FAIL;
			}
			tradeLog.setDoneTime((new Timestamp(System.currentTimeMillis())));

			// 更新交易记录次数
			this.userTradeRecordProxy.addTradCount(tradeLog.getBuyserUid());
			this.userTradeRecordProxy.addTradCount(tradeLog.getSellerUid());
		}
		// 付款
		else if (TradeLogConstants.PAY_STATUS_HAVE_PAY.equals(payStatus)) {
			tradeLog.setPayTime(new Timestamp(System.currentTimeMillis()));
		}
		// 买家取消
		else if (TradeLogConstants.PAY_STATUS_BUY_CANCEL.equals(payStatus)) {
			tradeLog.setCancelTime(new Timestamp(System.currentTimeMillis()));

			// 更新交易记录次数
			this.userTradeRecordProxy.reduceTradCount(tradeLog.getBuyserUid());
		}

		tradeLog.setPayStatus(payStatus);
		tradeLog.setUpdateTime(new Timestamp(System.currentTimeMillis()));
		this.tradeLogDao.updateTradeLog(tradeLog);
		log.info("TradeLogServiceImpl.updateOrder() success");
		return 0;
	}

	@Override
	public Long saveComplainLog(String orderNumber, Integer uid,
			Integer complainUid, String complainContent) {
		ComplainLog complainLog = new ComplainLog();
		complainLog.setOrderNumber(orderNumber);
		complainLog.setUid(uid);
		complainLog.setComplainUid(complainUid);
		complainLog.setComplainStatus(TradeLogConstants.COMPLAIN_STATUS_ING);
		complainLog.setComplainContent(complainContent);
		complainLog.setCreateTime(new Timestamp(System.currentTimeMillis()));
		complainLog.setUpdateTime(new Timestamp(System.currentTimeMillis()));
		Long complainLogId = this.complainLogDao.saveComplainLog(complainLog);
		log.info("TradeLogServiceImpl.saveComplainLog() success! saveId:{}",
				complainLogId);
		return complainLogId;
	}

	@Override
	public ComplainDetailDto getComplainDetail(String orderNumber) {
		ComplainLog complainLog = this.complainLogDao
				.getComplainLogByOrdernumber(orderNumber);
		if (complainLog == null) {
			return null;
		}

		ComplainDetailDto dto = new ComplainDetailDto();
		dto.setComplainStatus(complainLog.getComplainStatus());
		dto.setComplainContent(complainLog.getComplainContent());
		dto.setResultContent(complainLog.getResultContent());
		dto.setCreateTime(DateFormateUtils.formate(complainLog.getCreateTime()));
		dto.setUpdateTime(DateFormateUtils.formate(complainLog.getUpdateTime()));
		return dto;
	}

	@Override
	public void complainCancel(String orderNumber) {
		this.updateComplainStatus(orderNumber,
				TradeLogConstants.COMPLAIN_STATUS_CANEL);
	}

	@Override
	public void complainDone(String orderNumber) {
		this.updateComplainStatus(orderNumber,
				TradeLogConstants.COMPLAIN_STATUS_DONE);
	}

	@Override
	public void complainFail(String orderNumber) {
		this.updateComplainStatus(orderNumber,
				TradeLogConstants.COMPLAIN_STATUS_FAIL);
	}

	private void updateComplainStatus(String orderNumber, Integer complainStatus) {
		ComplainLog complainLog = this.complainLogDao
				.getComplainLogByOrdernumber(orderNumber);
		if (complainLog == null) {
			return;
		}

		complainLog.setComplainStatus(complainStatus);
		complainLog.setUpdateTime(new Timestamp(System.currentTimeMillis()));
		this.complainLogDao.updateComplainLog(complainLog);
	}
}
